#include "stdafx.h"
#include "YWinsockEx.h"


namespace ysimple_network
{
	YWinSockEx::YWinSockEx(void)
	{
		
	}


	YWinSockEx::~YWinSockEx(void)
	{
		WSACleanup();
	}

	YWinSockEx& YWinSockEx::getInstance()
	{
		static YWinSockEx _ins;
		return _ins;
	}


	HRESULT YWinSockEx::StartUp()
	{
		WSADATA wsaData;	
		if (0 != WSAStartup(MAKEWORD(2,2), &wsaData))
		{
			return WSAGetLastError();
		}

		GUID guidAcceptEx = WSAID_ACCEPTEX;
		GUID guidDisconnectEx = WSAID_DISCONNECTEX;
		GUID guidGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
		GUID guidConnectEx = WSAID_CONNECTEX;
		GUID guidTransmitFile = WSAID_TRANSMITFILE;

		HRESULT nResult = GetExtentionWinsockApi(guidAcceptEx, (LPVOID*)&lpfnAcceptEx);
		if (S_OK != nResult)
		{
			return nResult;
		}
		nResult = GetExtentionWinsockApi(guidDisconnectEx, (LPVOID*)&lpfnDisconnectEx);
		if (S_OK != nResult)
		{
			return nResult;
		}

		nResult = GetExtentionWinsockApi(guidTransmitFile, (LPVOID*)&lpfnTransmitFile);
		if (S_OK != nResult)
		{
			return nResult;
		}

		nResult = GetExtentionWinsockApi(guidConnectEx, (LPVOID*)&lpfnConnectEx);
		if (S_OK != nResult)
		{
			return nResult;
		}
		nResult = GetExtentionWinsockApi(guidGetAcceptExSockaddrs, (LPVOID*)&lpfnGetAcceptExSocketAddrs);
		if (S_OK != nResult)
		{
			return nResult;
		}

		return S_OK;
	}

	HRESULT YWinSockEx::GetExtentionWinsockApi( GUID& apiGuid, LPVOID* lpWinsockApiFunction )
	{
		SOCKET socket = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,0);
		HRESULT result;
		DWORD dwBytes;
		result = WSAIoctl(socket, 
			SIO_GET_EXTENSION_FUNCTION_POINTER,
			&apiGuid,
			sizeof(GUID),
			lpWinsockApiFunction,
			sizeof(lpWinsockApiFunction),
			&dwBytes,
			NULL,
			NULL
			);

		closesocket(socket);

		if (result == SOCKET_ERROR )
		{
			return WSAGetLastError();
		}

		return S_OK;
	}

	BOOL YWinSockEx::AcceptEx( __in SOCKET sListenSocket, __in SOCKET sAcceptSocket, __in PVOID lpOutputBuffer, __in DWORD dwReceiveDataLength, __in DWORD dwLocalAddressLength, __in DWORD dwRemoteAddressLength, __out LPDWORD lpdwBytesReceived, __in LPOVERLAPPED lpOverlapped )
	{
		return lpfnAcceptEx(sListenSocket, sAcceptSocket, lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength, lpdwBytesReceived, lpOverlapped);
	}

	BOOL YWinSockEx::DisconnectEx( __in SOCKET hSocket, __in LPOVERLAPPED lpOverlapped, __in DWORD dwFlags, __in DWORD reserved )
	{
		return lpfnDisconnectEx(hSocket, lpOverlapped, dwFlags, reserved);
		//::shutdown( hSocket,SD_SEND ); 
		//return ::TransmitFile(hSocket, NULL, 0, 0, lpOverlapped, NULL,  TF_DISCONNECT | TF_REUSE_SOCKET);
	}

	void YWinSockEx::GetAcceptExSockaddrs( __in PVOID lpOutputBuffer, __in DWORD dwReceiveDataLength, __in DWORD dwLocalAddressLength, __in DWORD dwRemoteAddressLength, __out LPSOCKADDR *LocalSockaddr, __out LPINT LocalSockaddrLength, __out LPSOCKADDR *RemoteSockaddr, __out LPINT RemoteSockaddrLength )
	{
		lpfnGetAcceptExSocketAddrs(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength, RemoteSockaddr, RemoteSockaddrLength);
	}

	BOOL PASCAL YWinSockEx::ConnectEx( __in SOCKET s, __in const struct sockaddr *name, __in int namelen, __in_opt PVOID lpSendBuffer, __in DWORD dwSendDataLength, __out LPDWORD lpdwBytesSent, __in LPOVERLAPPED lpOverlapped )
	{
		return lpfnConnectEx(s, name, namelen, lpSendBuffer, dwSendDataLength, lpdwBytesSent, lpOverlapped);
	}

	BOOL YWinSockEx::TransmitFile( SOCKET hSocket, HANDLE hFile, DWORD nNumberOfBytesToWrite, DWORD nNumberOfBytesPerSend, LPOVERLAPPED lpOverlapped, LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, DWORD dwFlags )
	{
		return lpfnTransmitFile(hSocket, hFile, nNumberOfBytesToWrite, nNumberOfBytesPerSend, lpOverlapped, lpTransmitBuffers, dwFlags);
	}

}
